#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: xaoyaoyao
@contact: xaoyaoyao@aliyun.com
@file: music163_spider.py
@time: 2018/08/26
"""

import scrapy
import time, re
from scrapy.http import Request
from scrapy.linkextractors import LinkExtractor
from scrapy.http.response.html import HtmlResponse
from article_spider.items import CommentItem
from article_spider.spiders.dynamic.js_spider import JSSpider
from article_spider.utils.tools import Tools


class Music163Spider(JSSpider):
    name = 'music163'
    allowed_domains = ['music.163.com']
    start_urls = [
        'https://music.163.com/#/discover/playlist/?cat={}',
    ]
    allowed_types = ['华语']
    ## 歌手列表
    start_singer_urls = [
        'https://music.163.com/#/artist?id={}',
    ]
    allowed_singer_types = {
        'Beyond': 11127,
        '张韶涵': 10562,
        '王菲': 9621,
        '张学友': 6460,
        '王杰': 5358,
        '邓紫棋':7763
    }

    ## 榜单
    start_top_urls = [
        'https://music.163.com/#/discover/toplist?id={}',
    ]
    allowed_top_types = {
        '云音乐飙升榜': 19723756,
        '云音乐新歌榜': 3779629,
        '内地榜': 64016
    }

    ## 专辑
    start_album_urls = [
        'https://music.163.com/#/album?id={}',
    ]
    allowed_album_types = {
        "我是歌手第四季 歌王之战": 34608091,
        "我是歌手第四季 第3期": 34469022,
        "我是歌手第一季 第6期": 2298011,
        "我是歌手第四季 第10期": 34569090,
        "我是歌手第二季 半决赛": 2774162,
        "我是歌手第三季 第12期": 3142053,
        "我是歌手第三季 总决赛": 3142085,
        "我是歌手第一季 第5期": 2290034,
        "我是歌手第三季 第4期": 3142035,
        "我是歌手 2015巅峰会": 3142088,
        "我是歌手第四季 第4期": 34477266,
        "我是歌手第二季 第3期": 2786862,
        "我是歌手第二季 第8期": 2786867,
        "我是歌手第四季 第1期": 34429065,
        "我是歌手第三季 第6期": 3142067,
        "我是歌手第三季 第5期": 3142050,
        "我是歌手第三季 第2期": 3142018,
        "我是歌手第三季 第9期": 3142080,
        "我是歌手第四季 第2期": 34436149,
        "我是歌手第四季 第6期": 34497112,
        "我是歌手第四季 第7期": 34524032,
        "我是歌手第四季 第5期": 34478239,
        "我是歌手第二季 双年巅峰会": 2786417,
        "我是歌手第二季 第7期": 2786866,
        "我是歌手第三季 第7期": 3142071,
        "我是歌手第三季 第11期": 3142079,
        "我是歌手第一季 第11期": 2374056,
        "我是歌手第三季 第8期": 3142078,
        "我是歌手第三季 第10期": 3142069,
        "我是歌手第一季 总决赛": 2415003,
        "我是歌手第三季 第3期": 3142024,
        "我是歌手第四季 第12期": 34589726,
        "我是歌手第三季 第1期": 3142014,
        "我是歌手第二季 第9期": 2786868,
        "我是歌手第二季 第5期": 2786864,
        "我是歌手第四季 第8期": 34527400,
        "我是歌手第一季 第2期": 2282020,
        "我是歌手第二季 第2期": 2786861,
        "我是歌手第一季 第12期": 2396284,
        "我是歌手第四季 第9期": 34527772,
        "我是歌手第四季 双年巅峰会": 34611474,
        "我是歌手第一季 第1期": 2282021,
        "我是歌手第二季 第1期": 2786853,
        "我是歌手第四季 第11期": 34589180,
        "我是歌手第二季 总决赛": 2785218,
        "我是歌手第一季 第7期": 2302089,
        "我是歌手第一季 第10期": 2365002,
        "我是歌手第二季 第6期": 2786865,
        "我是歌手第二季 第4期": 2786863,
        "我是歌手第一季 第9期": 2353004,
        "我是歌手第二季 第10期": 2786869,
        "我是歌手第一季 第3期": 2290005,
        "我是歌手第一季 第8期": 2315090,
        "我是歌手第一季 第4期": 2290028,
        "我是歌手第二季 突围赛": 2786870
    }

    iframe = 'contentFrame'

    def start_requests(self):
        for i in range(1, 2):
            for key, val in self.allowed_album_types.items():
                url = str(self.start_album_urls[0]).format(val)
                time.sleep(1)
                yield scrapy.Request(url=url, encoding='utf-8', callback=self.parse_play, meta={'_type': key})
            time.sleep(5)
            for key, val in self.allowed_top_types.items():
                url = str(self.start_top_urls[0]).format(val)
                time.sleep(1)
                yield scrapy.Request(url=url, encoding='utf-8', callback=self.parse_play, meta={'_type': key})
            time.sleep(5)
            for key, val in self.allowed_singer_types.items():
                url = str(self.start_singer_urls[0]).format(val)
                time.sleep(1)
                yield scrapy.Request(url=url, encoding='utf-8', callback=self.parse_play, meta={'_type': key})
            time.sleep(5)
            for c in self.allowed_types:
                url = str(self.start_urls[0]).format(c)
                time.sleep(1)
                yield scrapy.Request(url=url, encoding='utf-8', callback=self.parse_list, meta={'_type': c})

    def parse_list(self, response):
        current_url = response.url
        self.logger.info('[Music163Spider] This is an item page! %s', current_url)
        try:
            d_link = LinkExtractor(
                    restrict_xpaths='//ul[@id="m-pl-container"]//li//a[@class="msk"]')
            if d_link:
                links = d_link.extract_links(response)
                if links:
                    self.logger.info('[Music163Spider] The links >> %s ', links)
                    for detail_link in links:
                        if detail_link:
                            yield Request(url=detail_link.url, callback=self.parse_play,
                                          meta={'_type': response.meta['_type']})
        except Exception as e:
            self.logger.error("[Music163Spider] parse_list error. The msg %s", str(e))

    def parse_play(self, response):
        current_url = response.url
        self.logger.info('[Music163Spider] This is an item page! %s', current_url)
        try:
            d_link = LinkExtractor(
                    restrict_xpaths='//div[@class="f-cb"]//div[@class="ttc"]//span[@class="txt"]/a')
            if d_link:
                links = d_link.extract_links(response)
                if links:
                    self.logger.info('[Music163Spider] The links >> %s ', links)
                    for detail_link in links:
                        if detail_link:
                            yield Request(url=detail_link.url, callback=self.parse_song,
                                          meta={'_type': response.meta['_type']})
        except Exception as e:
            self.logger.error("[Music163Spider] parse_play error. The msg %s", str(e))

    def parse_song(self, response):
        _type = response.meta['_type']
        comment_item = self.__parse_info__(response, _type)
        try:
            if comment_item and comment_item['comments'] and len(comment_item['comments']) > 0:
                yield comment_item
            ## 下一页
            next_page = self.browser.find_element_by_link_text('下一页')
            if next_page:
                class_attr = next_page.get_attribute('class')
                if class_attr is None or 'js-disabled' in str(class_attr):
                    pass
                else:
                    yield self.parse_comment_list(_type)
        except Exception as e:
            self.logger.error("[Music163Spider] parse_song error. The msg %s", str(e))
            yield comment_item

    def parse_comment_list(self, _type):
        while True:
            next_page = self.browser.find_element_by_link_text('下一页')
            if next_page:
                class_attr = next_page.get_attribute('class')
                if class_attr is None or 'js-disabled' in str(class_attr):
                    break
                else:
                    next_page.click()
                    time.sleep(2)
                    page_source = self.browser.page_source
                    response = HtmlResponse(url=self.browser.current_url, body=page_source, encoding='utf-8')
                    comment_item = self.__parse_info__(response, _type)
                    if comment_item and comment_item['comments'] and len(comment_item['comments']) > 0:
                        yield comment_item
            else:
                break

    def __parse_info__(self, response, _type):
        comment_item = CommentItem()
        current_url = response.url
        self.logger.info('[Music163Spider] This is an item page! %s', current_url)
        current_url = response.url
        comment_item['name'] = '网易云音乐'
        comment_item['type'] = _type
        comment_item['cata'] = _type
        comment_item['url'] = current_url
        comment_item['domain'] = Tools.domain(current_url)
        try:
            rt_title = response.css('div.cnt div.hd div.tit em.f-ff2::text').extract()
            title = ''
            if rt_title and len(rt_title) > 0:
                title = rt_title[0]
            comment_item['title'] = title
            ## author
            rt_author = response.css('div.cnt p.des.s-fc4 a.s-fc7::text').extract()
            author = ''
            if rt_author and len(rt_author) > 0:
                author = rt_author[0]
            comment_item['author'] = author
            ## content
            rt_content_1 = response.css('#lyric-content::text').extract()
            rt_content_2 = response.css('#flag_more::text').extract()
            content = ''
            if rt_content_1:
                for c_text in rt_content_1:
                    content += str(c_text) + '\n'
                    content = content.replace('　', '')
            if rt_content_2:
                for c_text in rt_content_2:
                    content += str(c_text) + '\n'
                    content = content.replace('　', '')
            comment_item['content'] = content
            ## comments
            rt_comments = response.css('div.cntwrap div.cnt.f-brk::text').extract()
            comments = []
            if rt_comments and len(rt_comments) > 0:
                for i in range(len(rt_comments)):
                    rt = re.sub('[^0-9a-zA-Z\u4e00-\u9fa5。·，,！？：［］～：；＝、]+', '', rt_comments[i])
                    if rt and len(rt) > 0:
                        content = {
                            'content': rt,
                            'score': None
                        }
                        comments.append(content)
            comment_item['comments'] = comments
            self.logger.info('comment_item >> %s', comment_item)
            return comment_item
        except Exception as e:
            self.logger.error("[Music163Spider] parse_song error. The msg %s", str(e))
            return None
